package com.sangmo.fts.training.service;

import com.sangmo.boot.framework.common.errors.ServiceException;
import com.sangmo.boot.framework.common.errors.StandardErrors;
import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.data.filter.NativeQueryBuilder;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.data.filter.ValueFilter;
import com.sangmo.boot.framework.plugin.dataview.crud.service.DelegateViewService;
import com.sangmo.boot.framework.plugin.dataview.crud.service.ViewService;
import com.sangmo.boot.framework.plugin.dataview.spi.jpa.NativeQueryBuilderFactory;
import com.sangmo.fts.clazz.model.Clazz;
import com.sangmo.fts.clazz.service.ClazzEntityService;
import com.sangmo.fts.clazz.service.ClazzService;
import com.sangmo.fts.common.authority.AuthorityFilterChain;
import com.sangmo.fts.common.authority.Rights;
import com.sangmo.fts.common.authority.sql.WhereModifier;
import com.sangmo.fts.teacher.model.Examination;
import com.sangmo.fts.teacher.service.ExaminationService;
import com.sangmo.fts.training.interfaces.ExaminationTeamCreation;
import com.sangmo.fts.training.interfaces.TeamUpdate;
import com.sangmo.fts.training.model.Team;
import com.sangmo.fts.training.model.Teammate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class TeamService extends DelegateViewService<Team> {

    @Autowired
    private TeamEntityService teamEntityService;

    @Autowired
    private TeammateEntityService teammateEntityService;

    @Autowired
    private ClazzService clazzService;

    @Autowired
    private ExaminationService examinationService;

    @Override
    protected ViewService<Team> getEntityService() {
        return teamEntityService;
    }

    public PageResult<Team> clazzSearch(PageSearch ps) {
        WhereModifier modifier = AuthorityFilterChain.getInstance().createNativeModifier("a", Team.class, Rights.READ);
        Long currentUserId = (Long) UserSession.getUserInterface().getId();
        ps.getFilters().add(new ValueFilter("examinationId", ValueFilter.OP_IS_NULL, true));
        ps.getFilters().add(new ValueFilter("endTime", ValueFilter.OP_GT, System.currentTimeMillis()));

        NativeQueryBuilder builder = NativeQueryBuilderFactory.create()
                .putAlias("a", Team.class)
                .selectForm("SELECT a.* FROM team a ")
                .where(ps)
                .where(modifier.getSql()).putVariables(modifier.getVariables())
                .setAggregateWith("order by (CASE a.created_by WHEN "+currentUserId+" THEN 1 ELSE 0 END) DESC,a.created_time DESC")
                .transform(Team.class);
        return builder.buildPage();


    }

    public Team createByExaminationId(ExaminationTeamCreation creation) {
        Long currentUserId = (Long) UserSession.getUserInterface().getId();
        Examination exam = examinationService.checkExamAccess(creation.getExaminationId(), currentUserId);
        Team entity = new Team();
        entity.setExaminationId(creation.getExaminationId());
        entity.setBusinessType(exam.getBusinessType());
        entity.setEndTime(exam.getEndTime());
        return teamEntityService.createWithData(entity, creation);
    }

    public Team updateByExaminationId(Long examinationId, TeamUpdate obj) {
        Long currentUserId = (Long) UserSession.getUserInterface().getId();
        examinationService.checkExamAccess(examinationId, currentUserId);
        return teamEntityService.update(examinationId, obj);
    }

    public PageResult<Team> examinationSearch(Long examinationId, PageSearch ps) {
        WhereModifier modifier = AuthorityFilterChain.getInstance().createNativeModifier("a", Team.class, Rights.READ);
        Long currentUserId = (Long) UserSession.getUserInterface().getId();
        examinationService.checkExamAccess(examinationId, currentUserId);
        ps.getFilters().add(new ValueFilter("examinationId", ValueFilter.OP_EQ, examinationId));

        NativeQueryBuilder builder = NativeQueryBuilderFactory.create()
                .putAlias("a", Team.class)
                .selectForm("SELECT a.* FROM team a ")
                .where(ps)
                .where(modifier.getSql()).putVariables(modifier.getVariables())
                .setAggregateWith("order by (CASE a.created_by WHEN "+currentUserId+" THEN 1 ELSE 0 END) DESC,a.created_time DESC")
                .transform(Team.class);
        return builder.buildPage();
    }

    public void checkTeamValid(Long teamId, Long userId) {
        if (null == teamId) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.team.enter.teamId.notNull");
        }
        Team team = this.get(teamId);
        List<Teammate> teammates = teammateEntityService.findByTeamId(teamId);
        List<Long> teammateUserIds = teammates.stream().map(Teammate::getUserId).collect(Collectors.toList());
        if (!teammateUserIds.contains(userId)) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.team.enter.permit.disabled");
        }
        if (team.getEndTime().compareTo(new Date()) < 0) {
            throw new ServiceException(StandardErrors.CLIENT_ERROR.getStatus(), "error.team.endTime.expired");
        }
    }

    public void checkExaminationTeamValid(Long examinationId, Long teamId) {

    }

}
